14.2.3 部署应用

在部署应用之前,有几个前置处理需要完成。

  • Swarm模式 :应用将采用Docker Stack部署,而Stack依赖Swarm模式。
  • 标签 :某个Swarm worker节点需要自定义标签。
  • 密钥 :应用所需的密钥需要在部署前创建完成。
1.搭建应用实验环境

在本节中会完成基于Linux的三节点Swarm集群搭建,同时能满足上面应用的全部前置依赖。完成之后,实验环境如图14.4所示。

90.png

图14.4 示例环境

接下来内容分为3个步骤。

(1)创建新的Swarm。

(2)添加节点标签。

(3)创建密钥。

首先创建新的三节点Swarm集群。

(1)初始化Swarm。

在读者期望成为Swarm管理节点的机器上,运行下面的命令。

$ docker swarm init
Swarm initialized: current node (lhma...w4nn) is now a manager.
<Snip>

(2)添加工作节点。

复制前面输出中出现的 docker swarm join 命令。将复制内容粘贴到工作节点上并运行。

//Worker 1 (wrk-1)
wrk-1$ docker swarm join --token SWMTKN-1-2hl6...-...3lqg 172.31.40.192:2377
This node joined a swarm as a worker.
//Worker 2 (wrk-2)
wrk-2$ docker swarm join --token SWMTKN-1-2hl6...-...3lqg 172.31.40.192:2377
This node joined a swarm as a worker.

(3)确认当前Swarm由一个管理节点和两个工作节点构成。在管理节点中运行下面的命令。

$ docker node ls
ID            HOSTNAME  STATUS    AVAILABILITY   MANAGER STATUS
lhm...4nn *   mgr-1     Ready     Active         Leader
b74...gz3     wrk-1     Ready     Active
o9x...um8     wrk-2     Ready     Active

Swarm集群目前就绪。

payment_gateway 服务配置了部署约束,限制该服务只能运行在有 pcidss=yes 标签的工作节点之上。本步骤中将在 wrk-1 上添加该节点标签。

在现实世界中,添加该标签之前必须将某个Docker节点按PCI规范进行标准化。但是,这只是一个实验环境,所以就暂且跳过这一过程,直接将标签添加到 wrk-1 节点。

在Swarm管理节点运行下面的命令。

(1)添加节点标签到wrk-1。

$ docker node update --label-add pcidss=yes wrk-1

Node标签只在Swarm集群之内生效。

(2)确认节点标签。

$ docker node inspect wrk-1
[
{
    "ID": "b74rzajmrimfv7hood6l4lgz3",
    "Version": {
        "Index": 27
    },
    "CreatedAt": "2018-01-25T10:35:18.146831621Z",
    "UpdatedAt": "2018-01-25T10:47:57.189021202Z",
    "Spec": {
        "Labels": {
            "pcidss": "yes"
        },
        <Snip>

wrk-1 工作节点现在已经配置完成,所以该节点可以运行 payment_gateway 服务副本了。

应用定义了4个密钥,这些都需要在应用部署前创建。

  • postgress_password
  • staging_token
  • revprox_cert
  • revprox_key

在管理节点运行下面的命令,来创建这些密钥。

(1)创建新的键值对。

密钥中有3个是需要加密key的。在本步骤中会创建加密key,下一步会将加密key放到Docker密钥文件当中。

$ openssl req -newkey rsa:4096 -nodes -sha256 \
  -keyout domain.key -x509 -days 365 -out domain.crt

(2)创建 revprox_certrevprox_key 以及 postgress_password 密钥。

$ docker secret create revprox_cert domain.crt
cqblzfpyv5cxb5wbvtrbpvrrj
$ docker secret create revprox_key domain.key
jqd1ramk2x7g0s2e9ynhdyl4p
$ docker secret create postgres_password domain.key
njpdklhjcg8noy64aileyod6l

(3)创建stage_token密钥。

$ echo staging | docker secret create staging_token -
sqy21qep9w17h04k3600o6qsj

(4)列出所有密钥。

$ docker secret ls
ID          NAME                CREATED             UPDATED
njp...d6l   postgres_password   47 seconds ago      47 seconds ago
cqb...rrj   revprox_cert        About a minute ago  About a minute ago
jqd...l4p   revprox_key         About a minute ago  About a minute ago
sqy...qsj   staging_token       23 seconds ago      23 seconds ago

上面已经完成了全部的前置准备。是时候开始部署应用了!

2.部署示例应用

如果还没有代码,请先复制应用的GitHub仓库到Swarm管理节点。

$ git clone https://github.com/dockersamples/atsea-sample-shop-app.git
Cloning into 'atsea-sample-shop-app'...
remote: Counting objects: 636, done.
Receiving objects: 100% (636/636), 7.23 MiB | 3.30 MiB/s, done. remote:
Total 636 (delta 0), reused 0 (delta 0), pack-reused 636 Resolving
deltas: 100% (197/197), done.
Checking connectivity... done.
$ cd atsea-sample-shop-app

现在已经拥有了源码,可以开始部署应用了。

Stack通过 docker stack deploy 命令完成部署。基础格式下,该命令允许传入两个参数。

  • Stack文件的名称。
  • Stack的名称。

应用的GitHub仓库中包含一个名为docker-stack.yml的Stack文件。这里会使用该文件。本书中为Stack起名seastack,如果读者不喜欢,也可以选择其他名称。

在Swarm管理节点的 atsea-sample-shop-app 目录下运行下面的命令。

部署Stack(应用)。

$ docker stack deploy -c docker-stack.yml seastack
Creating network seastack_default
Creating network seastack_back-tier
Creating network seastack_front-tier
Creating network seastack_payment
Creating service seastack_database
Creating service seastack_appserver
Creating service seastack_visualizer
Creating service seastack_payment_gateway
Creating service seastack_reverse_proxy

读者可以运行 docker network ls 以及 docker service ls 命令来查看应用的网络和服务情况。

下面是命令输出中几个需要注意的地方。

网络是先于服务创建的。这是因为服务依赖于网络,所以网络需要在服务启动前创建。

Docker将Stack名称附加到由他创建的任何资源名称前作为前缀。在本例中,Stack名为 seastack ,所以所有资源名称的格式都如: seastack_<resource> 。例如, payment 网络的名称是 seastack_payment 。而在部署之前创建的资源则没有被重命名,比如密钥。

另一个需要注意的点是出现了新的名为 seastack_default 的网络。该网络并未在Stack文件中定义,那为什么会创建呢?每个服务都需要连接到网络,但是 visualizer 服务并没有指定具体的网络。因此,Docker创建了名为 seastack_default 的网络,并将 visualizer 连接到该网络。

读者可以通过两个命令来确认当前Stack的状态。 docker stack ls 列出了系统中全部Stack,包括每个Stack下面包含多少服务。 docker stack ps <stack-name> 针对某个指定Stack展示了更详细的信息,例如期望状态以及当前状态。下面一起来了解下这两条命令。

$ docker stack ls
NAME                SERVICES
Seastack            5
$ docker stack ps seastack
NAME                         NODE    DESIRED STATE   CURRENT STATE
seastack_reverse_proxy.1     wrk-2   Running         Running 7 minutes ago
seastack_payment_gateway.1   wrk-1   Running         Running 7 minutes ago
seastack_visualizer.1        mgr-1   Running         Running 7 minutes ago
seastack_appserver.1         wrk-2   Running         Running 7 minutes ago
seastack_database.1          wrk-2   Running         Running 7 minutes ago
seastack_appserver.2         wrk-1   Running         Running 7 minutes ago

在服务启动失败时, docker stack ps 命令是首选的问题定位方式。该命令展示了Stack中每个服务的概况,包括服务副本所在节点、当前状态、期望状态以及异常信息。从下面的输出信息中能看出 reverse_proxy 服务在 wrk-2 节点上两次尝试启动副本失败。

$ docker stack ps seastack
NAME                NODE      DESIRED    CURRENT ERROR
                              STATE      STATE
reverse_proxy.1     wrk-2     Shutdown   Failed  "task: non-zero exit (1)"
\_reverse_proxy.1   wrk-2     Shutdown   Failed  "task: non-zero exit (1)"

如果想查看具体某个服务的详细信息,可以使用 docker service logs 命令。读者需要将服务名称/ID或者副本ID作为参数传入。如果传入服务名称或ID,读者可以看到所有服务副本的日志信息。如果传入的是副本ID,读者只会看到对应副本的日志信息。

下面的 docker service logs 命令展示了 seastack_reverse_proxy 服务的全部副本日志,其中包含了前面输出中的两次副本启动失败的日志。

$ docker service logs seastack_reverse_proxy
seastack_reverse_proxy.1.zhc3cjeti9d4@wrk-2 | [emerg] 1#1: host not found...
seastack_reverse_proxy.1.6m1nmbzmwh2d@wrk-2 | [emerg] 1#1: host not found...
seastack_reverse_proxy.1.6m1nmbzmwh2d@wrk-2 | nginx: [emerg] host not found..
seastack_reverse_proxy.1.zhc3cjeti9d4@wrk-2 | nginx: [emerg] host not found..
seastack_reverse_proxy.1.1tmya243m5um@mgr-1 | 10.255.0.2 "GET / HTTP/1.1" 302

输出内容为了适应页面展示,已经经过裁剪,但是读者还是可以看到全部3个服务副本的日志(两个启动失败,1个正在运行)。每行的开始都是副本的名称,包括服务名称、副本序号、副本ID以及副本所在主机的名称。接下来是具体的日志输出。

注:

读者可能已经注意到前面日志中全部副本的序号都是1。这是因为Docker每次只创建一个副本,并且只有当前面的副本启动失败时才会创建新的。

因为输出内容经过裁剪,所以具体原因很难明确,但看起来前两次副本启动失败原因是其依赖的某个服务仍然在启动中(一种启动时服务间依赖导致的竞争条件)。

读者可以继续跟踪日志( --follow ),查看日志尾部内容( --tail ),或者获取额外的详细信息( --details )。

现在Stack已经启动并且处于运行中,看一下如何管理stack。

results matching ""

    No results matching ""